/**
* Copyright (c) By zengqh.
*
* This program is just for fun or demo, in the hope that it  
* will be useful, you can redistribute it and/or modify freely.
*
* Time: 2013/03/30
* File: ProgramGen.h
* Blog: http://www.cnblogs.com/zengqh/
**/

#pragma once

#include "RenderDef.h"
#include "RenderContext.h"

namespace HY
{
class Program;
class VertexShader;
class PixelShader;

class ProgramGen
{
public:
	class Flags
	{
	public:
		Flags()
			: vs_flags_(0)
			, ps_flags_(0)
		{

		}

		void reset()
		{
			vs_flags_ = 0;
			ps_flags_ = 0;
			vs_defs_.clear();
			ps_defs_.clear();
		}

		void addVSFlag(uint32 flag, const std::string& def)
		{
			if (!(vs_flags_ & flag))
			{
				vs_flags_ |= flag;
				vs_defs_.push_back(def);
			}
		}

		void addPSFlag(uint32 flag, const std::string& def)
		{
			if (!(ps_flags_ & flag))
			{
				ps_flags_ |= flag;
				ps_defs_.push_back(def);
			}
		}

		uint32 getVSFlags() const
		{
			return vs_flags_;
		}

		uint32 getPSFlags() const
		{
			return ps_flags_;
		}

		const std::vector<std::string>& getVSDefs() const
		{
			return vs_defs_;
		}

		const std::vector<std::string>& getPSDefs() const
		{
			return ps_defs_;
		}

	protected:
		uint32						vs_flags_;
		std::vector<std::string>	vs_defs_;
		uint32						ps_flags_;
		std::vector<std::string>	ps_defs_;
	};

	struct GeneratedProgram
	{
		Program*		pro;
		uint32			vs_flags;
		uint32			ps_flags;
		void*			user_data;
	};

public:
	ProgramGen(const std::string& vs_str, const std::string& ps_str);

	virtual ~ProgramGen();

	const std::string& getVSStr() const;
	const std::string& getPSStr() const;
	GeneratedProgram* getProgram(const Flags& flags);

protected:
	VertexShader* findVS(const ProgramGen::Flags& flags);
	PixelShader* findPS(const ProgramGen::Flags& flags);
	GeneratedProgram* findProgram(const ProgramGen::Flags& flags);
	VertexShader* createVS(const ProgramGen::Flags& flags);
	PixelShader* createPS(const ProgramGen::Flags& flags);
	
private:
	ProgramGen(const ProgramGen& src);
	ProgramGen& operator=(const ProgramGen& src);

protected:
	std::string							vs_str_;
	std::string							ps_str_;
	std::vector<VertexShader*>			vs_list_;
	std::map<uint32, VertexShader*>		vs_map_;
	std::vector<PixelShader*>			ps_list_;
	std::map<uint32, PixelShader*>		ps_map_;
	std::vector<GeneratedProgram*>		pro_list_;
	std::map<uint64, GeneratedProgram*>	pro_map_;
};

}